UNIT wlw;
	{lifted from MacApp's WriteLnWindow}
	{Copyright 1985, 1986 Apple Computer, Inc}

INTERFACE

{$R-} {$D+}

USES
	 MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,	 
	{$LOAD} PasLibIntf;

CONST
	kWWEol = CHR($0D);
	kForceDepth = 10;

TYPE
	WrForceOptions = (forceOn, forceOff, forceUnchanged);

VAR gDebugWindowPtr:	WindowPtr;
	gWrToWindow:		BOOLEAN;	{set to TRUE to enable writelns to window}
	gWrToFile:			BOOLEAN;	{set to TRUE to enable writelns to file}
		{both are initialized to TRUE in WWInit}

{All public procedure begin with WW (for WritelnWindow)}
PROCEDURE WWInit(numLines, numCharsPerLine: INTEGER);
	{Call this once at the start of your program.}

PROCEDURE WWNew(bounds: Rect; windowTitle: Str255; goAway: BOOLEAN; visible: BOOLEAN;
				outputFont, outputSize: INTEGER);
	{Call this to create a WriteLn window with given title.
		goAway is TRUE iff you want a go away box (IF the user clicks the go away box,
			the window will be hidden but not freed);
		visible is TRUE iff you want the window to be visible initially;
		outputFont & output size define the font to use
		}

PROCEDURE WWForceOutput(wrToWindow, wrToFile: WrForceOptions);
PROCEDURE WWEndForce;
	{Since it is now possible that one part of the program disables writelns to the window, you
		might want to guarantee that certain writelns appear in the window.  WWForceOutput saves
		the values of gWrToWindow & gWrToFile on a stack (depth = kForceDepth), and sets
		these values according to the parameters.  WWEndForce simply pops the stack.}

FUNCTION  WWRedirect(vRefnum: INTEGER; fileName: Str255): OSErr;
	{If you call this, then subsequent writelns will be sent to the indicated file.  (Assuming
		writing to the file is enabled. Pass '' for the fileName to close any open file.}

FUNCTION  WWReadCh: CHAR;
FUNCTION  WWReadLn(buffer: Ptr; byteCount: INTEGER): LONGINT;
PROCEDURE WWAddText(textBuf: Ptr; byteCount: INTEGER);

	{Call before SizeWindow if you need to resize the debug window programmatically}
PROCEDURE WWInvalGrowBox;
	{Call after SizeWindow if you need to resize the debug window programmatically}
PROCEDURE WWGrown;

	{Call the following procedures in response to events for the WriteLnWindow.
		(Test the window receiving the event against gDebugWindowPtr.}
PROCEDURE WWActivateEvent(modifiers: INTEGER);
PROCEDURE WWMouseDown(where: INTEGER; pt: Point; modifiers: INTEGER);
PROCEDURE WWUpdateEvent;
PROCEDURE WWScroll(howManyLines: INTEGER); {for UTrace use; negative arg scrolls backwards}

PROCEDURE IDUWritelnWindow; {Writeln UWritelnWindow's compile time.}

FUNCTION WWFirstLGlob: LongInt;
FUNCTION WWLastLGlob: LongInt;
FUNCTION WWFirstGlob: LongInt;
FUNCTION WWLastGlob: LongInt;

IMPLEMENTATION

{$R-}
{$D+}

CONST
	kWWHMargin = 5;
	kWWVMargin = 10;

	_CODEV = 1; 		{console device number}

TYPE	HText = ^PText;
		PText = ^AText;
		AText = PACKED ARRAY [0..10000] OF CHAR;

		HLineLens = ^PLineLens;
		PLineLens = ^ALineLens;
		ALineLens = ARRAY[0..10000] OF INTEGER;

		ForceState = RECORD
			toWindow:	BOOLEAN;
			toFile: 	BOOLEAN;
			END;

	IEFilePath =	STRING;
	IEFilePathPtr = ^IEFilePath;

	IEFRefNum = 	LONGINT;

VAR gLines: 		INTEGER;						{number of lines saved}
	gPerLine:		INTEGER;						{number of characters per line}
	gTotal: 		INTEGER;						{number of characters in all lines together}

	gText:			HText;							{the ring buffer: blanks pad each line to 80 chars}
	gLineLens:		HLineLens;						{# of real characters in each line; gLinesLens^^[0]
														is # of characters in the line that begins with
														gText^^[0]}

	gFirst: 		INTEGER;						{where in the ring buffer the top line starts}
	gLast:			INTEGER;						{where in the ring buffer the bottom line starts}
	gPos:			INTEGER;						{number of characters so far in the bottom line}

	gHeight:		INTEGER;						{font height}
	gLnAscent:		INTEGER;						{font ascent}
	gWidMax:		INTEGER;						{font char width (must be monospaced)}
	gSBars: 		ARRAY[VHSelect] OF ControlHandle;	{the window scroll bars}
	gScrollOffset:	Point;							{the position to which we are scrolled}
	gViewSize:		Point;							{total view size}
	gEndOfText: 	Point;							{the pen position after drawing all the lines}

	gStdDrag:		Rect;
	gStdSize:		Rect;
	gOrthogonal:	ARRAY[VHSelect] OF VHSelect;
	gWRec:			WindowRecord;
	gARgn:			RgnHandle;

	gGotRefnum: 	BOOLEAN;
	gRefnum:		INTEGER;					{refnum for redirect output}
	gVRefNum:		INTEGER;					{likewise, vrefnum}

	gForceStack:	ARRAY[1..kForceDepth] OF ForceState;
	gForcePtr:		INTEGER;


FUNCTION  GetSaveVisRgn: RgnHandle; FORWARD;

PROCEDURE WWInstall; FORWARD;
FUNCTION  WWBaseLine(ln: INTEGER): INTEGER; FORWARD;
PROCEDURE WWDoScrolling; FORWARD;
PROCEDURE WWDraw; FORWARD;
PROCEDURE WWNewLine; FORWARD;
PROCEDURE WWShowPoint(pt: Point); FORWARD;
PROCEDURE WWTrackScroll(aControl: ControlHandle; partCode: INTEGER); FORWARD;


{$S WWSeg}
FUNCTION WWFirstLGlob: LongInt;
BEGIN WWFirstLGlob := ORD(@gLines); END;

{$S WWSeg}
FUNCTION WWLastLGlob: LongInt;
BEGIN WWLastLGlob := ORD(@gForcePtr); END;

{$S WWSeg}
FUNCTION WWFirstGlob: LongInt;
BEGIN WWFirstGlob := ORD(@gDebugWindowPtr); END;

{$S WWSeg}
FUNCTION WWLastGlob: LongInt;
BEGIN WWLastGlob := ORD(@gWrToFile); END;


{$S WWSeg}
FUNCTION  GetSaveVisRgn: RgnHandle;
	CONST	addr	=	$09F2;
	TYPE	pRgn = ^RgnHandle;
	VAR 	pSaveVisRgn:	pRgn;
BEGIN
	pSaveVisRgn := pRgn(addr);
	GetSaveVisRgn := pSaveVisRgn^;
END;


{$S WWSeg}
FUNCTION  LongerSide(VAR r: Rect): VHSelect;
BEGIN
	WITH r DO
		IF (bottom - top) >= (left - right) THEN
			LongerSide := v
		ELSE
			LongerSide := h;
END;


{$S WWSeg}
PROCEDURE WindowFocus;
BEGIN
	SetPort(gDebugWindowPtr);
	SetOrigin(0, 0);
	ClipRect(thePort^.portRect);
END;


{$S WWSeg}
PROCEDURE ContentFocus;
	VAR r:	Rect;
BEGIN
	SetPort(gDebugWindowPtr);
	SetOrigin(gScrollOffset.h, gScrollOffset.v);
	r := thePort^.portRect;
	WITH r DO
		BEGIN
		right := right - 15;
		bottom := bottom - 15;
		END;
	ClipRect(r);
END;


{$S WWInit}
PROCEDURE WWInit(numLines, numCharsPerLine: INTEGER);
	VAR i: INTEGER;
BEGIN
	gDebugWindowPtr := NIL;

	gGotRefnum := FALSE;
	gWrToWindow := TRUE;
	gWrToFile := TRUE;

	WWInstall;

	gForcePtr := 0;

	gLines := numLines;
	gPerLine := numCharsPerLine;
	gTotal := gLines * gPerLine;

	gText := HText(NewHandle(gTotal));
	IF gText = NIL THEN
		BEGIN
		WriteLn('Not enough memory to allocate the Debug Window''s Line Array: ', gLines:1, '*', gPerLine:1);
		EXIT(WWInit);
		END;

	gLineLens := HLineLens(NewHandle(gLines*SIZEOF(INTEGER)));
	IF gLineLens = NIL THEN
		BEGIN
		DisposHandle(Handle(gText));
		WriteLn('Not enough memory to allocate the Debug Window''s LineLen Array: ', gLines:1);
		EXIT(WWInit);
		END;

	FOR i := 0 TO gLines-1 DO
		gLineLens^^[i] := 0;

	gFirst := 0;
	gLast := gTotal - gPerLine;
	gPos := 0;

	gOrthogonal[v] := h;
	gOrthogonal[h] := v;
END;


{$S WWInit}
PROCEDURE WWNew(bounds: Rect; windowTitle: Str255; goAway: BOOLEAN; visible: BOOLEAN;
				outputFont, outputSize: INTEGER);
	VAR fInfo:		FontInfo;
		control:	ControlHandle;
		i:			INTEGER;
		aLine:		StringHandle;
		vhs:		VHSelect;
		savePort:	GrafPtr;
BEGIN
	GetPort(savePort);
	IF gDebugWindowPtr = NIL THEN
		BEGIN
		gDebugWindowPtr := NewWindow(@gWRec, bounds, windowTitle, visible, documentProc,
									POINTER(-1), goAway, 0);

		WITH screenBits.bounds DO
			BEGIN
			SetRect(gStdDrag, 4, 24, right - 4, bottom - 4);	{this is suggested in Inside Macintosh}
			SetRect(gStdSize, 20, 20, right, bottom - 20);		{arbitrary Min size; Max size is screen}
			END;

		gARgn := NewRgn;

		SetPt(gEndOfText, kWWHMargin, WWBaseLine(gLines));

		SetPort(gDebugWindowPtr);
		TextFont(outputFont);
		TextSize(outputSize);
		GetFontInfo(fInfo);

		WITH fInfo DO
			BEGIN
			gHeight := ascent + descent + leading;
			gLnAscent := ascent;
			gWidMax := widMax;
			SetPt(gViewSize, (2 * kWWHMargin) + (gPerLine * widMax), (2 * kWWVMargin) + (gHeight * gLines));
			END;

		{scroll bars}
		FOR vhs := v TO h DO
			gSBars[vhs] := NewControl(gDebugWindowPtr, gDebugWindowPtr^.portRect, '', FALSE,
								0, 0, 1, scrollBarProc, 0);

		{SetPt(gScrollOffset, 0, 0);}
		gScrollOffset := Point(0);

		{put the scroll bars in the right place}
		WWGrown;

		{force an update}
		WWUpdateEvent;

		{scroll to the end, in case there is some information that needs to be displayed}
		SetCtlValue(gSBars[v], MAXINT);
		WWDoScrolling;
		END;
	SetPort(savePort);
END;


{$S WWSeg}
PROCEDURE WWActivateEvent(modifiers: INTEGER);
	VAR r:			Rect;
		vhs:		VHSelect;
		anSBar: 	ControlHandle;
		savePort:	GrafPtr;
BEGIN
	GetPort(savePort);

	WindowFocus;

	r := thePort^.portRect;

	FOR vhs := v TO h DO
		BEGIN
		anSBar := gSBars[vhs];
		IF Odd(modifiers) THEN
			ShowControl(anSBar)
		ELSE
			HideControl(anSBar);
		END;

	DrawGrowIcon(gDebugWindowPtr);

	SetPort(savePort);
END;


{$S WWSeg}
PROCEDURE WWAddText(textBuf: Ptr; byteCount: INTEGER);
	CONST BS = 8;
	VAR gotEOL: 	BOOLEAN;
		b:			QDByte;
		startPtr:	Ptr;
		startCount: INTEGER;
		ps: 		PenState;
		savePort:	GrafPtr;
		deleted:	BOOLEAN;
		r:			Rect;

		count:		LONGINT;
BEGIN
	IF gWrToFile THEN
		IF gGotRefnum THEN
			BEGIN
			count := byteCount;
			IF FSWrite(gRefnum, count, textBuf) <> noErr THEN
				BEGIN
				{??? do something here ???}
				END;
			END;

	IF gWrToWindow THEN
		BEGIN
		IF gDebugWindowPtr <> NIL THEN
			GetPort(savePort);

		deleted := FALSE;

		WHILE byteCount > 0 DO
			BEGIN
			gotEOL := FALSE;
			startPtr := textBuf;
			startCount := byteCount;

			WHILE (byteCount > 0) AND (gPos < gPerLine) AND (NOT gotEOL) DO
				BEGIN
				b := QDPtr(textBuf)^;
				byteCount := byteCount - 1;
				textBuf := Ptr(LONGINT(textBuf) + 1);

				IF b = ORD(kWWEol) THEN
					gotEOL := TRUE
				ELSE IF b <> BS THEN
					BEGIN
					gText^^[gLast+gPos] := CHAR(b);
					gPos := gPos + 1;
					END
				ELSE IF gPos > 0 THEN  {Backspace -- don't backspace past beginning of line!}
					BEGIN
					WITH gEndOfText DO
						BEGIN
						SetRect(r, h - gWidMax, v - gLnAscent, h, v + gHeight - gLnAscent);
						h := h - gWidMax;
						END;

					IF gDebugWindowPtr <> NIL THEN
						BEGIN
						ContentFocus;
						EraseRect(r);
						END;

					gPos := gPos - 1;
					deleted := TRUE;
					END
				ELSE
					deleted := TRUE;
				END;

			IF NOT deleted AND (gDebugWindowPtr <> NIL) THEN
				BEGIN
				ContentFocus;
				MoveTo(gEndOfText.h, gEndOfText.v);
				DrawText(QDPtr(startPtr), 0, startCount - byteCount - ORD(gotEOL));
				GetPenState(ps);
				gEndOfText := ps.pnLoc;
				END;

			IF (gPos >= gPerLine) OR gotEOL THEN
				BEGIN
				gLineLens^^[gLast DIV gPerLine] := gPos;	{remember # characters in this line}

				WWNewLine;
				IF (byteCount > 0) AND (NOT gotEOL) THEN
					BEGIN
					gText^^[gLast] := 'É';
					gPos := 1;
					END;
				END;
			END;

		gLineLens^^[gLast DIV gPerLine] := gPos;

		IF gDebugWindowPtr <> NIL THEN
			SetPort(savePort);
		END;
END;


{$S WWSeg}
FUNCTION  WWBaseLine(ln: INTEGER): INTEGER;
BEGIN
	WWBaseLine := kWWVMargin + (ln - 1) * gHeight;
END;


{$S WWSeg}
PROCEDURE WWDoScrolling;
	VAR newOffset:		Point;
		delta:			Point;
BEGIN
	newOffset.v := GetCtlValue(gSBars[v]);
	delta.v := gScrollOffset.v - newOffset.v;
	newOffset.h := GetCtlValue(gSBars[h]);
	delta.h := gScrollOffset.h - newOffset.h;

	IF (delta.h <> 0) OR (delta.v <> 0) THEN
		BEGIN
		ContentFocus;

		ScrollRect(thePort^.portRect, delta.h, delta.v, gARgn);
		gScrollOffset := newOffset;

		InvalRgn(gARgn);

		WWUpdateEvent;
		END;
END;


{$S WWSeg}
PROCEDURE WWDraw;
	VAR i:		INTEGER;
		y:		INTEGER;
		start:	INTEGER;
		line:	INTEGER;
		ps: 	PenState;
BEGIN
	y := kWWVMargin;			{initial y corodinate}

	start := gFirst;			{offset to first character of next line to draw}
	line := start DIV gPerLine; {index into gLineLens array for next line to draw; always start DIV gPerLine}

	FOR i := 1 TO gLines DO
		BEGIN
		MoveTo(kWWHMargin, y);

		HLock(Handle(gText));
		DrawText(QDPtr(gText^), start, gLineLens^^[line]);
		HUnlock(Handle(gText));

		y := y + gHeight;
		start := start + gPerLine;
		line := line + 1;

		IF start = gTotal THEN
			BEGIN
			start := 0;
			line := 0;
			END;
		END;

	GetPenState(ps);			{remember position of last character drawn}
	gEndOfText := ps.pnLoc;
END;


{$S WWSeg}
PROCEDURE WWEndForce;
BEGIN
	IF gForcePtr <= 0 THEN
		BEGIN
		END
	ELSE
		BEGIN
		WITH gForceStack[gForcePtr] DO
			BEGIN
			gWrToWindow := toWindow;
			gWrToFile := toFile;
			END;
		gForcePtr := gForcePtr - 1;
		END;
END;


{$S WWSeg}
PROCEDURE WWForceOutput(wrToWindow, wrToFile: WrForceOptions);
BEGIN
	IF gForcePtr >= kForceDepth THEN
		BEGIN
		END
	ELSE
		BEGIN
		gForcePtr := gForcePtr + 1;

		WITH gForceStack[gForcePtr] DO
			BEGIN
			toWindow := gWrToWindow;
			toFile := gWrToFile;
			END;

		IF wrToWindow <> forceUnchanged THEN
			gWrToWindow := wrToWindow = forceOn;

		IF wrToFile <> forceUnchanged tHEN
			gWrToFile := wrToFile = forceOn;
		END;
END;


{$S WWSeg}
PROCEDURE WWGrown;
	VAR r:				Rect;
		vhs:			VHSelect;
		anSBar: 		ControlHandle;
		newMax: 		INTEGER;
		isVisible:		BOOLEAN;
		savePort:		GrafPtr;
BEGIN
	GetPort(savePort);

	WindowFocus;
	r.topLeft := Point(0);
	r.botRight := Point(0);
	ClipRect(r);

	FOR vhs := v TO h DO
		BEGIN
		anSBar := gSBars[vhs];

		r := thePort^.portRect;

		WITH r DO
			BEGIN
			{Calculate new position of scroll bar}
			topLeft.vh[vhs] := topLeft.vh[vhs] - 1;
			topLeft.vh[gOrthogonal[vhs]] := botRight.vh[gOrthogonal[vhs]] - 15;
			botRight.vh[vhs] := botRight.vh[vhs] - 14;
			botRight.vh[gOrthogonal[vhs]] := topLeft.vh[gOrthogonal[vhs]] + 16;

			{Move the scroll bar}
			MoveControl(anSBar, left, top);
			SizeControl(anSBar, right-left, bottom-top);

			newMax := gViewSize.vh[vhs] - (bottom - top);
			IF newMax < 0 THEN
				newMax := 0;
			SetCtlMax(anSBar, newMax);
			END;
		END;

	WWInvalGrowBox;

	WWDoScrolling;	{in case we are showing too much white space}

	SetPort(savePort);
END;


{$S WWSeg}
PROCEDURE WWInvalGrowBox;
	VAR r:	Rect;
BEGIN
	r.botRight := thePort^.portRect.botRight;
	WITH r DO
		BEGIN
		top := bottom - 15;
		left := right - 15;
		END;
	InvalRect(r);
END;


{$S WWSeg}
PROCEDURE WWMouseDown(where: INTEGER; pt: Point; modifiers: INTEGER);
	VAR r:				Rect;
		sizeStuff:		RECORD CASE INTEGER OF
							1:	(growResult: LONGINT);		{Information returned by GrowRect}
							2:	(newV,						{new vertical size}
								 newH: INTEGER);			{new horizontal size}
							3:	(newSize: Point);			{new size as a point}
						END;
		partCode:		INTEGER;
		whichControl:	ControlHandle;
		oldSize:		Point;
		savePort:		GrafPtr;
BEGIN
	GetPort(savePort);

	CASE where OF
		inDrag:
			DragWindow(gDebugWindowPtr, pt, gStdDrag);

		inGrow:
			BEGIN
			WindowFocus;

			WITH sizeStuff DO
				BEGIN
				WITH gDebugWindowPtr^.portRect, oldSize DO
					BEGIN
					h := right - left;
					v := bottom - top;
					END;

				growResult := GrowWindow(gDebugWindowPtr, pt, gStdSize);
				IF growResult <> 0 THEN
					BEGIN
					WWInvalGrowBox;
					SizeWindow(gDebugWindowPtr, newH, newV, TRUE);
					WWGrown;
					END;
				END;
			END;

		inGoAway:
			IF TrackGoAway(gDebugWindowPtr, pt) THEN
				HideWindow(gDebugWindowPtr);

		inContent:
			IF gDebugWindowPtr = FrontWindow THEN
				BEGIN
				WindowFocus;

				GlobalToLocal(pt);
				partCode := FindControl(pt, gDebugWindowPtr, whichControl);
				IF partCode <> 0 THEN
					CASE partCode OF
						inUpButton, inDownButton, inPageUp, inPageDown:
							partCode := TrackControl(whichControl, pt, @WWTrackScroll);
						inThumb:
							BEGIN
							partCode := TrackControl(whichControl, pt, NIL);
							WWDoScrolling;
							END;
						END;
				END
			ELSE
				SelectWindow(gDebugWindowPtr);
		END;  {CASE}

	SetPort(savePort);
END;


{$S WWSeg}
PROCEDURE WWNewLine;
	VAR savePort:		GrafPtr;
		i:				INTEGER;
		pt: 			Point;
		r:				Rect;
BEGIN
	GetPort(savePort);

	SetPt(pt, kWWHMargin, gEndOfText.v);
	WWShowPoint(pt);

	gLast := gFirst;
	gPos := 0;
	gLineLens^^[gLast DIV gPerLine] := gPos;	{remember # characters in new line}

	gFirst := gFirst + gPerLine;
	IF gFirst = gTotal THEN
		gFirst := 0;

	SetPt(gEndOfText, kWWHMargin, WWBaseLine(gLines));

	IF gDebugWindowPtr <> NIL THEN
		BEGIN
		ContentFocus;
		SetRect(r, kWWHMargin, kWWVMargin - gLnAscent, gViewSize.h, gEndOfText.v + gHeight - gLnAscent);
		ScrollRect(r, 0, -gHeight, gARgn);
		InvalRgn(gARgn);

		WWUpdateEvent;
		END;

	SetPort(savePort);
END;


FUNCTION  WWRedirect(vRefnum: INTEGER; fileName: Str255): OSErr;
	VAR err:	OSErr;
		append: BOOLEAN;
		x:		LONGINT;
BEGIN
	IF gGotRefnum THEN
		BEGIN
			{truncate the file to current position}
		err := GetFPos(gRefnum, x);
		err := SetEOF(gRefnum, x);

		IF FSClose(gRefnum) <> noErr THEN {??? error closing file ???};
		IF FlushVol(NIL, gVRefNum) <> noErr THEN {??? Another fine mess ???};
		gGotRefnum := FALSE;
		END;

	append := POS('>>', fileName) = 1;
	IF append THEN
		Delete(fileName, 1 ,2);

	IF fileName <> '' THEN
		BEGIN
		err := Create(fileName, vRefnum, 'MACA', 'TEXT');

		IF (err = noErr) OR (err = dupFNErr) THEN
			BEGIN
			err := FSOpen(fileName, vRefnum, gRefnum);
			gVRefNum := vRefNum;
			WWRedirect := err;

			gGotRefnum := err = noErr;

			IF gGotRefnum THEN
				IF append THEN
					BEGIN
					err := GetEOF(gRefnum, x);
					err := SetFPos(gRefnum, fsFromStart, x);
					END;
			END
		ELSE
			WWRedirect := err;
		END;
END;


PROCEDURE WWScroll(howManyLines: INTEGER);
	VAR val:		INTEGER;
		savePort:	GrafPtr;
BEGIN
	GetPort(savePort);
	val := GetCtlValue(gSBars[v]);
	IF ((howManyLines < 0) AND (val > GetCtlMin(gSBars[v]))) OR
	   ((howManyLines > 0) AND (val < GetCtlMax(gSBars[v]))) THEN
		BEGIN
		SetCtlValue(gSBars[v], val + howManyLines * gHeight);
		WWDoScrolling;
		END;
	SetPort(savePort);
END;


PROCEDURE WWShowPoint(pt: Point);
	VAR minToSee:	Point;
		deltaCd:	INTEGER;
BEGIN
	IF gDebugWindowPtr <> NIL THEN
		BEGIN
		WindowFocus;
	
		SetPt(minToSee, 50, gHeight);
	
		{the following code is actually better than writing a loop with VHSelect}
		WITH thePort^.portRect DO
			BEGIN
			deltaCd := pt.v + mintoSee.v - (bottom - 15 + gScrollOffset.v);
			IF deltaCd <= 0 THEN
				BEGIN
				deltaCd := pt.v - minToSee.v - (top + gScrollOffset.v);
				IF deltaCd >= 0 THEN
					deltaCd := 0;
				END;
			SetCtlValue(gSBars[v], GetCtlValue(gSBars[v]) + deltaCd);
	
			deltaCd := pt.h + mintoSee.h - (right - 15 + gScrollOffset.h);
			IF deltaCd <= 0 THEN
				BEGIN
				deltaCd := pt.h - minToSee.h - (left + gScrollOffset.h);
				IF deltaCd >= 0 THEN
					deltaCd := 0;
				END;
			SetCtlValue(gSBars[h], GetCtlValue(gSBars[h]) + deltaCd);
			END;
	
		WWDoScrolling;
		END;
END;


{$S WWSeg}
PROCEDURE WWTrackScroll(aControl: ControlHandle; partCode: INTEGER);
	VAR up: 		BOOLEAN;
		ctlValue:	INTEGER;
		vhs:		VHSelect;
		r:			Rect;
		delta:		INTEGER;
BEGIN
	IF partCode <> 0 THEN
		BEGIN
		up := (partCode = inUpButton) OR (partCode = inPageUp);
		ctlValue := GetCtlValue(aControl);

	  {avoid flicker in setting thumb, IF user tries to scroll past end}
		IF (up AND (ctlValue > GetCtlMin(aControl))) OR
		   (NOT up AND (ctlValue < GetCtlMax(aControl))) THEN
			BEGIN
			r := aControl^^.contrlRect;   {heap may compact when we call LongerSide}
			vhs := LongerSide(r);		  {this tells us which way we are scrolling}

			IF (partCode = inPageUp) OR (partCode = inPageDown) THEN
				WITH gDebugWindowPtr^.portRect DO
					delta := botRight.vh[vhs] - topLeft.vh[vhs] - gHeight
			ELSE
				delta := gHeight;

			IF up THEN
				delta := - delta;

			SetCtlValue(aControl, ctlValue + delta);
			WWDoScrolling;

			WindowFocus;
			END;
		END;
END;


{$S WWSeg}
PROCEDURE WWUpdateEvent;
	VAR savePort:		GrafPtr;
		saveSaveVisRgn: RgnHandle;
		saveVisRgn: 	RgnHandle;
BEGIN
	GetPort(savePort);

	saveSaveVisRgn := NewRgn;
	saveVisRgn := GetSaveVisRgn;

	CopyRgn(saveVisRgn, saveSaveVisRgn);

	BeginUpdate(gDebugWindowPtr);

	WindowFocus;

	EraseRect(thePort^.portRect);

	DrawGrowIcon(gDebugWindowPtr);
	DrawControls(gDebugWindowPtr);

	ContentFocus;
	WWDraw;

	EndUpdate(gDebugWindowPtr);

	CopyRgn(saveSaveVisRgn, saveVisRgn);
	DisposeRgn(saveSaveVisRgn);

	SetPort(savePort);
END;


{$S WWSeg}
FUNCTION WWReadCh: CHAR;
	VAR savePort:	GrafPtr;
		ch: 		CHAR;
		anEvent:	EventRecord;
		r:			Rect;
BEGIN
	GetPort(savePort);

	ContentFocus;

	WITH gEndOfText DO
		SetRect(r, h, v - gLnAscent, h + gWidMax, v + gHeight - gLnAscent);

	FillRect(r, black);
	REPEAT UNTIL GetOSEvent(keyDownMask+autoKeyMask, anEvent);
	EraseRect(r);

	ch := CHAR(BAND(anEvent.message, charCodeMask));

	WWReadCh := ch;

	SetPort(savePort);
END;


{$S WWSeg}
FUNCTION WWReadLn(buffer: Ptr; byteCount: INTEGER): LONGINT;
	CONST
		CR = 13;
		BS = 8;
	TYPE	PA1000 = PACKED ARRAY [0..999] OF CHAR;
			StrPtr = ^PA1000;
	VAR ch: 	CHAR;
		len:		INTEGER;
BEGIN
	len := 0;
	REPEAT
		ch := WWReadCh;
		IF ORD(ch) <> BS THEN
			BEGIN
			WWAddText(POINTER(ORD(@ch)+1), 1);
			StrPtr(buffer)^[len] := CHAR(ch);
			len := len + 1;
			END
		ELSE IF len > 0 THEN
			BEGIN
			WWAddText(POINTER(ORD(@ch)+1), 1);
			len := len - 1;
			StrPtr(buffer)^[len] := ' ';
			END
   UNTIL (ORD(ch)=CR) OR (len = byteCount);

   WWReadLn := len;
END;


PROCEDURE IDUWritelnWindow; {Writeln UWritelnWindow's compile time.}
BEGIN
	Writeln('UWritelnWindow of ', COMPDATE, ' @ ', COMPTIME);
END;


FUNCTION
	wwFAccess(fName: UNIV IEFilePathPtr; opCode: LONGINT; arg: UNIV LONGINT):
	LONGINT; C; EXTERNAL;
FUNCTION
	wwClose(fdesc: IEFRefNum):
	LONGINT; C; EXTERNAL;
FUNCTION
	wwRead(fdesc: IEFRefNum; bufp: UNIV LONGINT; count: LONGINT):
	LONGINT; C; EXTERNAL;
FUNCTION
	wwWrite(fdesc: IEFRefNum; bufp: UNIV LONGINT; count: LONGINT):
	LONGINT; C; EXTERNAL;
FUNCTION
	wwIoctl(fdesc: IEFRefNum; request: LONGINT; arg: UNIV LONGINT):
	LONGINT; C; EXTERNAL;

FUNCTION
	_addDevHandler(
		slot, dvName, dvFAccess, dvClose, dvRead, dvWrite, dvIoctl: LONGINT):
	LONGINT; C; EXTERNAL;

PROCEDURE WWInstall;
	VAR slot: LONGINT;
BEGIN
	slot := _addDevHandler(_CODEV, 0,
					ORD(@wwFAccess), ORD(@wwClose), 
					ORD(@wwRead), ORD(@wwWrite),
					ORD(@wwIoctl));
	PLsetvbuf(output, NIL, 64, 100);
END;


END.



